package com.electromagnetic.industry.software.manage.service.serviceimpl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.electromagnetic.industry.software.common.enums.AdminTypeEnum;
import com.electromagnetic.industry.software.common.enums.DataOwnEnum;
import com.electromagnetic.industry.software.common.enums.EffectFlagEnum;
import com.electromagnetic.industry.software.common.enums.EleDataTypeEnum;
import com.electromagnetic.industry.software.common.pojo.RespPageVO;
import com.electromagnetic.industry.software.common.resp.ElectromagneticResult;
import com.electromagnetic.industry.software.common.util.EleCommonUtil;
import com.electromagnetic.industry.software.common.util.ElectromagneticResultUtil;
import com.electromagnetic.industry.software.common.util.UserThreadLocal;
import com.electromagnetic.industry.software.manage.config.ElePropertyConfig;
import com.electromagnetic.industry.software.manage.mapper.EdFileInfoMapper;
import com.electromagnetic.industry.software.manage.mapper.UserMapper;
import com.electromagnetic.industry.software.manage.pojo.models.EdFileInfo;
import com.electromagnetic.industry.software.manage.pojo.models.User;
import com.electromagnetic.industry.software.manage.pojo.req.RecycleFileQueryDTO;
import com.electromagnetic.industry.software.manage.pojo.resp.FileRecycleQueryVO;
import com.electromagnetic.industry.software.manage.service.FileRecycleService;
import com.electromagnetic.industry.software.manage.service.FileSystemService;
import com.electromagnetic.industry.software.manage.service.PermissionService;
import com.electromagnetic.industry.software.manage.tasks.BackupHandler;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
public class FileRecycleServiceImpl implements FileRecycleService {

    @Resource
    private EdFileInfoMapper edFileInfoMapper;
    @Resource
    private PermissionService permissionService;
    @Resource
    private UserMapper userMapper;
    @Resource
    private CommonService commonService;
    @Resource
    private FileSystemService fileSystemService;
    @Resource
    private ElePropertyConfig elePropertyConfig;
    @Resource
    private BackupHandler backupHandler;

    @Override
    public ElectromagneticResult<?> list(RecycleFileQueryDTO pars) {

        LambdaQueryWrapper<EdFileInfo> queryWrapper = Wrappers.lambdaQuery(EdFileInfo.class)
                .select(EdFileInfo.class, file -> !StrUtil.equals(file.getColumn(), "file_content"))
                .eq(EdFileInfo::getAllDeleted, true)
                .eq(EdFileInfo::getPermanentDeleted, false)
                .eq(EdFileInfo::getDataType, EleDataTypeEnum.FILE.code)

                .eq(StrUtil.isNotEmpty(pars.getFileType()), EdFileInfo::getFileType, pars.getFileType())
                .orderByAsc(ObjUtil.equals(pars.getCreatedTime(), 0), EdFileInfo::getCreatedTime)
                .orderByDesc(ObjUtil.equals(pars.getCreatedTime(), 1), EdFileInfo::getCreatedTime)
                .orderByDesc(ObjUtil.isAllEmpty(pars.getCreatedTime(), pars.getVersionSort(), pars.getFileSizeSort(), pars.getFileNameSort(), pars.getUpdatedTime(), pars.getFileTypeSort()), EdFileInfo::getCreatedTime)
                .orderByAsc(ObjUtil.equals(pars.getVersionSort(), 0), EdFileInfo::getFileVersion)
                .orderByDesc(ObjUtil.equals(pars.getVersionSort(), 1), EdFileInfo::getFileVersion)

                .orderByAsc(ObjUtil.equals(pars.getFileSizeSort(), 0), EdFileInfo::getFileSize)
                .orderByDesc(ObjUtil.equals(pars.getFileSizeSort(), 1), EdFileInfo::getFileSize)

                .orderByAsc(ObjUtil.equals(pars.getFileNameSort(), 0), EdFileInfo::getFileName)
                .orderByDesc(ObjUtil.equals(pars.getFileNameSort(), 1), EdFileInfo::getFileName)

                .orderByAsc(ObjUtil.equals(pars.getUpdatedTime(), 0), EdFileInfo::getUpdatedTime)
                .orderByDesc(ObjUtil.equals(pars.getUpdatedTime(), 1), EdFileInfo::getUpdatedTime)

                .orderByAsc(ObjUtil.equals(pars.getFileTypeSort(), 0), EdFileInfo::getSort)
                .orderByDesc(ObjUtil.equals(pars.getFileTypeSort(), 1), EdFileInfo::getSort);


        if (StrUtil.isNotEmpty(pars.getKeyword())) {
            queryWrapper.and(qr -> qr.like(EdFileInfo::getFileName, pars.getKeyword())
                    .or()
                    .like(EdFileInfo::getFileCode, pars.getKeyword())
                    .or()
                    .like(EdFileInfo::getFileNote, pars.getKeyword()));
//                    .or()
//                    .like(EdFileInfo::getFileContent, pars.getKeyword()));
        }

        if (!UserThreadLocal.getAdminType().equals(AdminTypeEnum.SYSTEM.getValue())) {
            LambdaQueryWrapper<EdFileInfo> userPrjWrapper = Wrappers.<EdFileInfo>lambdaQuery()
                    .select(EdFileInfo::getId, EdFileInfo::getFileCode)
                    .eq(EdFileInfo::getDataOwn, DataOwnEnum.USER_FILE.code)
                    .eq(EdFileInfo::getEffectFlag, EffectFlagEnum.NOT_EFFECTIVE.code)
                    .eq(EdFileInfo::getAllDeleted, true)
                    .eq(EdFileInfo::getPermanentDeleted, false);
            List<String> ids = edFileInfoMapper.selectList(userPrjWrapper).stream().map(EdFileInfo::getFileCode).map(e -> e.substring(0, 6)).toList();
            List<String> accessibleTree = permissionService.getAccessibleTree();
            accessibleTree.addAll(ids);
            if (CollUtil.isNotEmpty(accessibleTree)) {
                queryWrapper.and(qr -> accessibleTree.forEach(e -> qr.or().likeRight(EdFileInfo::getFileCode, e)));
            }
        }
        Page<EdFileInfo> edFileInfoPage = this.edFileInfoMapper.selectPage(new Page<>(pars.getPageNum(), pars.getPageSize()), queryWrapper);
        long total = edFileInfoPage.getTotal();
        List<FileRecycleQueryVO> records = BeanUtil.copyToList(edFileInfoPage.getRecords(), FileRecycleQueryVO.class);

        List<String> filePaths = records.stream().map(FileRecycleQueryVO::getFilePath).toList();
        Map<String, String> filesPath = commonService.getFilesPath(filePaths);
        Map<String, String> userIdNameMap = getUserIdNameMap(records.stream().map(FileRecycleQueryVO::getUpdatedBy).toList());
        records.forEach(e -> {
            e.setDataOwner(DataOwnEnum.getEnumByCode(e.getDataOwn()).type);
            e.setFilePrjPath(filesPath.get(e.getFilePath()));
            e.setFileSizeShow(EleCommonUtil.convertFileSize(e.getFileSize()));
            e.setUserName(userIdNameMap.get(e.getUpdatedBy()));
        });
        UserThreadLocal.setSuccessInfo("", "", "查询所有删除文件成功");
        return ElectromagneticResultUtil.success(new RespPageVO<>(total, records));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ElectromagneticResult<?> remove(String fileId) {
        // 备份该文件
        List<EdFileInfo> edFileInfos = this.edFileInfoMapper.selectList(Wrappers.lambdaQuery(EdFileInfo.class)
                .select(EdFileInfo.class, file -> !StrUtil.equals(file.getColumn(), "file_content"))
                .eq(EdFileInfo::getFileId, fileId));
        for (EdFileInfo edFileInfo : edFileInfos) {
            String fileSysPath = commonService.getFileSysPath(edFileInfo.getId());
            if (!EleCommonUtil.isWinOs()) {
                backupHandler.backupFiles(fileSysPath);
            }
            String fileDbPath = commonService.getDbPath(edFileInfo.getFilePath());
            // 移动到tmp目录，七天后删除
            fileSystemService.moveFile(fileSysPath, elePropertyConfig.getEleTmpPath() + File.separator + new File(fileSysPath).getName());
            // 更新MySQL数据库
            this.edFileInfoMapper.update(new EdFileInfo(), Wrappers.lambdaUpdate(EdFileInfo.class)
                    .eq(EdFileInfo::getFileId, fileId)
                    .set(EdFileInfo::getEffectFlag, EffectFlagEnum.NOT_EFFECTIVE.code)
                    .set(EdFileInfo::getPermanentDeleted, true)
                    .set(EdFileInfo::getAllDeleted, true));
            UserThreadLocal.setSuccessInfo(edFileInfo.getParentId(), edFileInfo.getId(), "删除文件 {} 成功，文件id {}，文件路径 {}", edFileInfos.get(0).getFileName() + "." + edFileInfos.get(0).getFileType(), edFileInfo.getId(), fileDbPath);
            return ElectromagneticResultUtil.success("删除文件成功");
        }
        return ElectromagneticResultUtil.success("删除文件成功");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ElectromagneticResult<?> recover(String fileId) {

        List<EdFileInfo> edFileInfos = this.edFileInfoMapper.selectList(Wrappers.lambdaQuery(EdFileInfo.class)
                .select(EdFileInfo.class, file -> !StrUtil.equals(file.getColumn(), "file_content"))
                .orderByDesc(EdFileInfo::getFileVersion)
                .eq(EdFileInfo::getFileId, fileId)
                .last("limit 1"));
        EdFileInfo edFileInfo = edFileInfos.get(0);

        String parentId = edFileInfo.getParentId();
        Long count = this.edFileInfoMapper.selectCount(Wrappers.lambdaQuery(EdFileInfo.class)
                .eq(EdFileInfo::getParentId, parentId)
                .eq(EdFileInfo::getFileName, edFileInfo.getFileName())
                .eq(EdFileInfo::getFileType, edFileInfo.getFileType())
                .eq(EdFileInfo::getDataType, EleDataTypeEnum.FILE.code)
                .eq(EdFileInfo::getAllDeleted, false)
                .eq(EdFileInfo::getPermanentDeleted, false)
                .eq(EdFileInfo::getEffectFlag, EffectFlagEnum.EFFECT.code));
        if (count > 0) {
            return ElectromagneticResultUtil.fail("-1", "目录下存在相同名称和后缀的文件，恢复失败");
        }

        this.edFileInfoMapper.update(new EdFileInfo(), Wrappers.lambdaUpdate(EdFileInfo.class).set(EdFileInfo::getAllDeleted, false).eq(EdFileInfo::getFileId, fileId));
        this.edFileInfoMapper.update(new EdFileInfo(), Wrappers.lambdaUpdate(EdFileInfo.class).set(EdFileInfo::getEffectFlag, EffectFlagEnum.EFFECT.code).eq(EdFileInfo::getId, edFileInfo.getId()));
        UserThreadLocal.setSuccessInfo(edFileInfo.getParentId(), edFileInfo.getId(), "还原文件 {} 成功，文件id为 {}", edFileInfo.getFileName() + "." + edFileInfo.getFileType(), fileId);
        return ElectromagneticResultUtil.success("还原文件成功");
    }

    private Map<String, String> getUserIdNameMap(List<String> userIds) {
        Map<String, String> res = new HashMap<>();

        if (CollUtil.isEmpty(userIds)) {
            return res;
        }

        return userMapper.selectList(Wrappers.<User>lambdaQuery()
                        .select(User::getId, User::getUserName)
                        .in(User::getId, userIds))
                .stream().collect(Collectors.toMap(User::getId, User::getUserName));
    }

}
